package core

import (
	"context"
	"errors"
	"flow-calc/common"
	"flow-calc/core/log"
	"fmt"
	"sync"
)

/**
 *    Description: 管理全部的Function和Flow的池子
 *    Date: 2024/3/28
 */

var _poolOnce sync.Once

type kisPool struct {
	fnRouter    funcRouter
	fnLock      sync.RWMutex
	flowRouter  flowRouter
	flowLock    sync.RWMutex
	cInitRouter connInitRouter       // 连接初始化
	cInitLock   sync.RWMutex         // 连接初始化锁
	cTree       connTree             // 全部的connector管理路由
	connectors  map[string]Connector // 全部的connector对象
	cLock       sync.RWMutex         // cTree 锁
}

// 单例模式
var _pool *kisPool

// Pool 获取单例
func Pool() *kisPool {
	_poolOnce.Do(func() {
		// 创建kisPool对象
		_pool = new(kisPool)
		_pool.fnRouter = make(funcRouter)
		_pool.flowRouter = make(flowRouter)
		_pool.cTree = make(connTree)
		_pool.cInitRouter = make(connInitRouter)
		_pool.connectors = make(map[string]Connector)
	})
	return _pool
}

// AddFlow 注册添加flow流式管理器(不能重复添加相同的flow)
func (pool *kisPool) AddFlow(name string, flow Flow) {
	pool.flowLock.Lock()
	defer pool.flowLock.Unlock()
	if _, ok := pool.flowRouter[name]; !ok {
		pool.flowRouter[name] = flow
	} else {
		panic("flow name is exist")
	}
	log.Logger().Info("Add FlowRouter FlowName=%s\n", name)
}

func (pool *kisPool) GetFlow(name string) Flow {
	pool.flowLock.RLock()
	defer pool.flowLock.RUnlock()
	if flowObj, ok := pool.flowRouter[name]; ok {
		return flowObj
	} else {
		return nil
	}
}

// GetFlows 获取全部的Flow
func (pool *kisPool) GetFlows() []Flow {
	pool.flowLock.RLock()
	defer pool.flowLock.RUnlock()
	var flows []Flow
	for _, flow := range pool.flowRouter {
		flows = append(flows, flow)
	}
	return flows
}

// AddFaaS 注册添加FaaS函数,通过Function Name索引及注册
func (pool *kisPool) AddFaaS(fnName string, f FaaS) {
	pool.fnLock.Lock()
	defer pool.fnLock.Unlock()
	if _, ok := pool.fnRouter[fnName]; !ok {
		pool.fnRouter[fnName] = f
	} else {
		panic("FaaS 函数 name is exist")
	}
	log.Logger().Info("Add KisPool FuncName=%s", fnName)
}

// AddFaaSList 添加FaaS列表数据
func (pool *kisPool) AddFaaSList(List ...FaaSBody) {
	for _, body := range List {
		pool.AddFaaS(body.FuncName, body.Func)
	}
}

// CallFunction 调用FaaS函数
func (pool *kisPool) CallFunction(ctx context.Context, fnName string, flow Flow) error {
	pool.fnLock.RLock()
	defer pool.fnLock.RUnlock()
	if f, ok := pool.fnRouter[fnName]; ok {
		return f(ctx, flow)
	}
	return errors.New("FuncName: " + fnName + "函数没有被注册.")
}

// AddCaaSInit 注册添加connector初始化
func (pool *kisPool) AddCaaSInit(cName string, c ConnInit) {
	pool.cInitLock.Lock()
	defer pool.cInitLock.Unlock()
	if _, ok := pool.cInitRouter[cName]; !ok {
		pool.cInitRouter[cName] = c
	} else {
		panic("CaaS Init 函数 name is exist")
	}
	log.Logger().Info("AddCaaSInit CaaSName=%s", cName)
}

// CallCaaSInit 调度CaaSInit函数业务
func (pool *kisPool) CallCaaSInit(conn Connector) error {
	pool.cInitLock.RLock()
	defer pool.cInitLock.RUnlock()
	init, ok := pool.cInitRouter[conn.GetName()]
	if !ok {
		panic(errors.New(fmt.Sprintf("Init connector cName = %s ,没有被注册", conn.GetName())))
	}
	return init(conn)
}

// AddCaaS 注册添加connector业务
func (pool *kisPool) AddCaaS(cName string, fName string, mode common.FunMode, c CaaS) {
	pool.cLock.Lock()
	defer pool.cLock.Unlock()
	if _, ok := pool.cTree[cName]; !ok {
		// 首次进行注册二级树connSL
		pool.cTree[cName] = make(connSL)
		pool.cTree[cName][common.S] = make(connFuncRouter)
		pool.cTree[cName][common.L] = make(connFuncRouter)
	}
	if _, ok := pool.cTree[cName][mode][fName]; !ok {
		pool.cTree[cName][mode][fName] = c
	} else {
		panic(fmt.Sprintf("CaaS 业务函数 name is exist"))
	}
	log.Logger().Info("Add CaaS CName=%s, FName=%s, Mode =%s", cName, fName, mode)
}

// CallCaaS 调度CaaS业务
func (pool *kisPool) CallCaaS(ctx context.Context, flow Flow, conn Connector, args interface{}) error {
	pool.cLock.RLock()
	defer pool.cLock.RUnlock()
	fn := flow.GetExecFunction()
	fnConf := fn.GetConfig()
	if callBack, ok := pool.cTree[conn.GetName()][common.FunMode(fnConf.FMode)][fnConf.FName]; ok {
		return callBack(ctx, conn, fn, flow, args)
	}
	return errors.New(fmt.Sprintf("CName:%s FName:%s mode:%s 该connecter连接器没有被注册.", conn.GetName(), fnConf.FName, fnConf.FMode))
}
